﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr.Runtime;
using Antlr.Runtime.Tree;
using System.Collections;
namespace Magic.Framework.OQL.Expressions
{

    public class Expression : Antlr.Runtime.Tree.ITree, IEnumerable<Expression>, IExpression
    {
        protected internal IList<Expression> _children;
        protected IToken token;
        private int startIndex;
        private int stopIndex;
        private int childIndex;

        public int ChildIndex
        {
            get { return childIndex; }
            set { childIndex = value; }
        }
        private Expression parent;

        #region constructors
        public Expression()
        {
            this.startIndex = -1;
            this.stopIndex = -1;
        }
        public Expression(IToken t)
        {
            this.startIndex = -1;
            this.stopIndex = -1;
            this.token = t;
        }
        public Expression(Expression node)
        {
            this.startIndex = -1;
            this.stopIndex = -1;
            this.token = node.token;
        }
        #endregion


        #region members for ITree
        ///<summary>
        ///Parent of the node
        ///</summary>
        public ITree Parent
        {
            get 
            {
                return parent;
            }
            set {
                parent = (Expression)value;
            }
        }

        /// <summary>
        /// Index position of first char of this expression in input character stream.
        /// </summary>
        public int CharPositionInLine
        {
            get
            {
                if ((this.token == null) || (this.token.CharPositionInLine == -1))
                    return this.ChildCount > 0 ? this.GetChild(0).CharPositionInLine : 0;
                return this.token.CharPositionInLine;
            }
        }


        /// <summary>
        /// Count of expressions in sub tree
        /// </summary>
        public int ChildCount
        {
            get
            {
                return this._children == null ? 0 : this._children.Count;
            }
        }

        /// <summary>
        /// Indecates whether this expression is a null one.
        /// <para>True: it's a null expression, which means the root of the tree it representing has no token.</para>
        /// <para>False: it's not a null expression, which means the root of the tree it representing has a token.</para>
        /// </summary>
        public bool IsNil
        {
            get
            {
                return this.token == null;
            }
        }

        /// <summary>
        /// Line number of first token of this expression in input character stream.
        /// </summary>
        public int Line
        {
            get
            {
                if ((this.token == null) || (this.token.Line == 0))
                    return this.ChildCount > 0 ? this.GetChild(0).Line : 0;
                return this.token.Line;
            }
        }
        /// <summary>
        /// The token text if this is not a null expression, else it's empty string.
        /// </summary>
        public string Text
        {
            get
            {
                return this.ToString();
            }
        }

        /// <summary>
        /// Index position of first token of this expression in input token stream(output of lexer).
        /// <remarks>The value is set by ANTLR Runtime using <see cref="ITreeAdaptor"/></remarks>
        /// </summary>
        public int TokenStartIndex
        {
            get
            {
                return this.startIndex == -1 && this.token != null ? this.token.TokenIndex : this.startIndex;
            }
            set
            {
                this.startIndex = value;
            }
        }

        /// <summary>
        /// Index position of last token of this expression in input token stream(output of lexer).
        /// <remarks>The value is set by ANTLR Runtime using <see cref="ITreeAdaptor"/></remarks>
        /// </summary>
        public int TokenStopIndex
        {
            get
            {
                return this.stopIndex == -1 && this.token != null ? this.token.TokenIndex : this.stopIndex;
            }
            set
            {
                this.stopIndex = value;
            }
        }

        /// <summary>
        /// The token type if this is not a null expression, else it's 0.
        /// </summary>
        public int Type
        {
            get
            {
                return this.token == null ? 0 : this.token.Type;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        void ITree.AddChild(ITree t)
        {
            if (t == null) return;
            if (t is Expression) this.AddChild(t as Expression);
            else throw new Exception("Parameter of ITree.AddChild is not derived from Expression.");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="t"></param>
        public virtual void AddChild(Expression t)
        {
            this.InternalAddChild(t);
        }
        protected void InternalAddChild(Expression t)
        {
            if (t == null) return;

            if (t.IsNil)
            {
                if ((this._children != null) && (this._children == t._children))
                    throw new InvalidOperationException("attempt to add child list to itself");
                if (t._children != null)
                {
                    if (this._children != null)
                    {
                        int count = t._children.Count;
                        for (int i = 0; i < count; i++)
                            this._children.Add(t._children[i]);
                    }
                    else
                        this._children = t._children; //what's the relationship between t and this in this case???
                }
            }
            else
            {
                if (this._children == null)
                    this._children = this.CreateChildrenList();
                this._children.Add(t);
            }
        }
        protected IList<Expression> CreateChildrenList()
        {
            return new List<Expression>();
        }

        /// <summary>
        /// Get a copy of the root of this expression(not including subtrees).
        /// </summary>
        /// <returns></returns>
        ITree ITree.DupNode()
        {
            return this.DupNode();
        }
        /// <summary>
        /// Get a copy of the root of this expression(not including subtrees).
        /// </summary>
        /// <returns></returns>
        public virtual Expression DupNode()
        {
            return new Expression(this);
        }

        public object DeleteChild(int i)
        {
            if (i < _children.Count)
            {
                Object tmp = _children.ElementAt(i);
                _children.RemoveAt(i);
                return tmp;
            }
            return null;
        }
        public void FreshenParentAndChildIndexes()
        {
 
        }
        public ITree GetAncestor(int ttype)
        {
            Expression tmp = this;
            while (tmp.parent != null)
            {
                if (tmp.parent.Type == ttype)
                    return tmp.parent;
                tmp = tmp.parent;
            }
            return null;
        }
        public IList<ITree> GetAncestors()
        {
            IList<ITree> ancestors = new List<ITree>();
            Expression  tmp = this;
            while (tmp.parent != null)
            {
                ancestors.Add(tmp.parent);
                tmp = tmp.parent;
            }
            return ancestors;
        }
        public bool HasAncestor(int ttype)
        {
            Expression tmp = this;
            while (tmp.parent != null)
            {
                if (tmp.parent.Type == ttype)
                    return true;
                tmp = tmp.parent;
            }
            return false;
        }
        public void ReplaceChildren(int startChildIndex, int stopChildIndex, object t)
        {
            int limit = Math.Min(ChildCount, startChildIndex);
            for (int i = startChildIndex; i < limit; ++i)
            {
                _children.RemoveAt(i);
                _children.Insert(i, (Expression)t);
            }
        }
        public void SetChild(int i, ITree t)
        {
            if (i < ChildCount)
            {
                _children.RemoveAt(i);
                _children.Insert(i, (Expression)t);
            }
        }
        /// <summary>
        /// Get a whole copy of this expression(including subtrees).
        /// </summary>
        /// <returns></returns>
       /* ITree ITree.DupTree()
        {
            return this.DupTree();
        }*/
        /// <summary>
        /// Get a whole copy of this expression(including subtrees).
        /// </summary>
        /// <returns></returns>
        public virtual Expression DupTree()
        {
            Expression tree = this.DupNode();
            for (int i = 0; this._children != null && i < this._children.Count; i++)
                tree.AddChild(this._children[i].DupTree());
            return tree;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        ITree ITree.GetChild(int i)
        {
            return this.GetChild(i);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public virtual Expression GetChild(int i)
        {
            return this._children == null || i < 0 || i >= this._children.Count ? null : this._children[i];
        }

        /// <summary>
        /// Return the token text if this is a null expression, else empty string.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.IsNil ? "" : this.token.Text;
        }

        /// <summary>
        /// The flat string of the tree of this expression.
        /// </summary>
        /// <returns></returns>
        public virtual string ToStringTree()
        {
            if ((this._children == null) || (this._children.Count == 0))
                return this.ToString();
            StringBuilder builder = new StringBuilder();
            if (!this.IsNil)
            {
                builder.Append("(");
                builder.Append(this.ToString());
                builder.Append(' ');
            }
            for (int i = 0; (this._children != null) && (i < this._children.Count); i++)
            {
                Expression tree = this._children[i];
                if (i > 0)
                    builder.Append(' ');
                builder.Append(tree.ToStringTree());
            }
            if (!this.IsNil)
                builder.Append(")");
            return builder.ToString();
        }

        #endregion


        #region members for IEnumerator
        /// <summary>
        /// No semantics for IText based expressions
        /// </summary>
        /// <returns></returns>
        public IEnumerator<Expression> GetEnumerator()
        {
            return new ExpressionEnumerator(this);
        }

        /// <summary>
        /// No semantics for IText based expressions
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return new ExpressionEnumerator(this);
        }
        #endregion


        #region members for Expression
        /// <summary>
        /// <para>Act as tree walker, emit the SQL text for this expression. </para>
        /// </summary>
        /// <param name="builder">The output for SQL text.</param>
        /// <param name="builder"></param>
        public virtual void VisitSql(ISqlVisitor visitor)
        {
            this.InternalVisitSql(visitor, true, " ");
        }
        protected void InternalVisitSql(ISqlVisitor visitor, bool delim, string delimiter)
        {
            for (int i = 0; this._children != null && i < this._children.Count; i++)
            {
                if (delim && i != 0)
                {
                    if (string.IsNullOrEmpty(delimiter) || delimiter.Length <= 0) visitor.Space();
                    else if (delimiter == " ") visitor.Space();
                    else visitor.Sql(delimiter);
                }
                this._children[i].VisitSql(visitor);
            }
        }
        public virtual void VisitCompile(ICompileVisitor visitor)
        {
            foreach (Expression exp in this)
                exp.VisitCompile(visitor);
        }

        public IToken Token
        {
            get { return this.token; }
        }

        /// <summary>
        /// todo:
        /// Give child a chance for specific process when adding 
        /// </summary>
        /// <param name="exp"></param>
        public virtual void AfterAddChild(Expression exp)
        {
        }
        #endregion


    }
}
